<?php

namespace app;


/**
 * Class PluginParse
 * 解析插件类
 */
class PluginParse extends PluginPhp
{

    use \app\core\Instance;


    // 消息变量名
    private $msgName = 'Message';

    /**
     * 指令列表
     * @var array
     */
    private $instruction = [];


    /**
     * 编译方法
     *
     * @param array $array 要编译的数组
     */
    public function toPhp($array)
    {

        //print_r($array);
        // 创建类
        $class = $this->addClass($array['className']);
        //            print_r($array);

        foreach ($array['code'] as $k => $v) {
            //print_r($v);
            $this->instruction[$v['methodName']] = $v['instruction'];

            $default = [];
            // 添加方法
            $this->method = $class->addMethod($v['methodName']);

            //创建Message变量
            $default[] = $this->method->addStringConcatAssignment('$Message', '');
            //添加
            $this->method->addStmt();
            // 逐行解析
            $temp = $this->analyse($v['code']);

            $temp[] = $this->addReturn('$Message');

            $stmts = array_merge($default, $temp);

            $this->method->stmts = $stmts;
        }


        //添加属性
        $this->addPropertyStatement('instruction', $this->instruction);
        $this->addPropertyStatement('remark', array_flip($array['remark']));

        $this->addUseStatement('app\\Route');
        $this->addUseStatement('app\\MathExpression');

        $code = $this->getCode();
        unset(
            $this->class,
            $this->methods,
            $this->method,
            $this->instruction,
            $this->property,
            $this->stmtsList
        );

        //print_r($this);
        return $code;

    }

    /**
     * 解析方法
     *
     * @param array $array 要解析的数组
     * @param bool $temp 是否临时
     */
    public function analyse($array)
    {

        $temp = [];
        foreach ($array as $k => $v) {
            //print_r($v);

            //if语句
            if (isset($v['type']) && $v['type'] == 'if') {
                $temp[] = $this->addCondition($v);
                continue;
            }

            //字符串
            if (isset($v['type']) && $v['type'] == 'string') {

                //print_r($v);
                //连接字符串
                if (is_array($v['code']) && isset($v['code']['type']) && $v['code']['type'] == 'concat') {
                    //print_r($v);
                    $temp[] = $this->addString($this->method->addConcatStatement(array_reverse($v['code']['code'])));

                } else if (is_array($v['code']) && isset($v['code']['type']) && $v['code']['type'] == 'fun') {
                    //print_r($this->method->addFunctionStatement($v['code']));
                    $temp[] = $this->addString($this->method->addFunctionStatement($v['code']));
                } else if (is_array($v['code']) && isset($v['code']['type']) && ($v['code']['type'] == 'array' || $v['code']['type'] == 'var' || $v['code']['type'] == 'maths')) {
                    $temp[] = $this->addString($this->method->analyse($v['code']));

                } else if (isset($v['code']['type'])) {
                    throw new \Exception('解析错误，string未定义的类型；' . $v['code']['type']);

                } else {

                    $temp[] = $this->addString($v['code']);

                }
                continue;
            }

            //设置变量
            if (isset($v['type']) && $v['type'] == 'setVar') {

                if (isset($v['code']['type']) && $v['code']['type'] == 'concat') {
                    $temp[] = $this->addString($this->method->addConcatStatement(array_reverse($v['code']['code'])), '$this->' . $v['varName']);
                } else if (isset($v['code']['type']) && $v['code']['type'] == 'fun') {
                    $temp[] = $this->addString($this->method->addFunctionStatement($v['code']), '$this->' . $v['varName']);
                } else if (isset($v['code']['type']) && ($v['code']['type'] == 'string' || $v['code']['type'] == 'var' || $v['code']['type'] == 'array' || $v['code']['type'] == 'maths')) {
                    $temp[] = $this->addString($this->method->analyse($v['code']), '$this->' . $v['varName']);
                    //print_r($temp);

                } else {
                    throw new \Exception('解析错误，serVar未定义的类型；' . $v['code']['type']);
                }

                //$temp[] = $this->addCondition($v);
                continue;
            }

            //获取变量
            if (isset($v['type']) && $v['type'] == 'var') {
                $temp[] = $this->addString($this->method->analyse($v));
                //echo "读取变量；";
                //print_r($v);
                continue;
            }

            //调用函数
            if (isset($v['type']) && $v['type'] == 'fun') {
                //print_r($v);
                $temp[] = $this->addString($this->method->addFunctionStatement($v));
                continue;
            }


            if (isset($v['type']) && $v['type'] == 'goto') {
                $temp[] = $this->method->analyse($v);
                continue;
            }

            if (isset($v['type']) && $v['type'] == 'label') {
                $temp[] = $this->method->analyse($v);
                continue;
            }

            if (isset($v['type']) && $v['type'] == 'json') {
                $temp[] = $this->method->analyse($v);
                continue;
            }

            //return
            if (isset($v['type']) && $v['type'] == 'return') {
                $temp[] = $this->addReturn('$Message');
                continue;
            }

            throw new \Exception('解析错误，未定义的类型；' . $v['type']);
        }
        //print_r($array);
        return $temp;
    }

    /**
     * 获取变量名
     *
     * @param string $string 字符串
     * @return string 变量名
     */
    public function getName($string)
    {
        return md5($string);
    }

    /**
     * 添加函数调用赋值
     *
     * @param array $v 要处理的数组
     * @param bool $temp 是否临时
     */
    public function addAssignFun($v)
    {
        $name = $this->getName($v['name']);
        $target = "this->_{$name}";
        $value = $this->getFun($v['code'][0]['code']);

        $this->method->addStringConcatAssignment($target, $value);

        return $this->method->tempStmt;
    }



    /**
     * 添加字符串处理
     */
    public function addString($string, $name = false)
    {
        $concat = false;
        if (!$name) {

            $concat = true;
            $name = '.$Message';
        }
        $this->method->addStringConcatAssignment($name, $string, $concat);
        //        print_r($this->method->tempStmt);
        return $this->method->tempStmt;
    }

    /**
     * 添加返回语句
     *
     * @param string $string 要返回的字符串
     */
    public function addReturn($string)
    {
        $this->method->addReturnStatement($string);
        return $this->method->tempStmt;
    }


    /**
     * 获取函数调用
     *
     * @param string $code 代码
     * @return array 函数调用的结果
     */
    public function getFun($code)
    {
        preg_match("/\\$(.*?)\\$/", $code[0], $match);
        $arrayFun = explode(" ", $match[1]);

        $funName = $arrayFun[0];
        switch ($funName) {
            case '读':
                unset($arrayFun[0]);
                $result = ['$this->read', $arrayFun];
                break;
            default:
                $result = [];
        }

        return $result;
    }

    /**
     * 添加条件语句处理
     *
     * @param array $code
     * 
     */
    public function addCondition($code)
    {
        $stmts = [];

        //条件语句
        $stmts['cond'] = $code['cond'];

        //if语句
        if (isset($code['code']['if'])) {
            $stmts['ifStmts'] = $this->analyse($code['code']['if']);
        }

        //elseif语句
        if (isset($code['code']['elseif'])) {
            $code['code']['elseif'] = array_reverse($code['code']['elseif']);
            foreach ($code['code']['elseif'] as $key => $elseif) {
                $stmts['elseIf'][$key]['cond'] = $elseif['cond'];
                $stmts['elseIf'][$key]['elseIfStmts'][] = $this->analyse($elseif['code']['if']);
            }
        }

        //else语句
        if (isset($code['code']['else'])) {
            $stmts['elseStmts'] = $this->analyse($code['code']['else']);
        }

        return $this->method->addIfStatement($stmts);

    }

}